import { Destroyable } from "earthsdk3";
import * as Cesium from "cesium";
import { ESJMaterialType } from "earthsdk3";
import { createTexture, setModelMaterial } from "earthsdk3-cesium";
Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyMjg1YjVhNi03MzQ3LTQ3Y2YtYmZkMi03Mzk1Y2U1ZjAxZjciLCJpZCI6NTg2MjYsImlhdCI6MTYyMzMxMTAyMH0.j1E0WhsWnSDeFGk2uTwzdb778ot_fsKO_pg2HNs3uuE"

const modes = {
    "sphere": "Sphere_10m",
    "cube": "Box_10m",
    "cylinder": "Cylinder_10m"
}
export class MaterialEditing extends Destroyable {
    public viewer?: Cesium.Viewer;
    public primitives: { [xx: string]: Cesium.Primitive } = {};
    public models: { [xx: string]: Cesium.Model } = {};
    public currentPrimitive!: Cesium.Primitive;
    public currentModel!: Cesium.Model;
    public lastMaterial?: { [xx: string]: ESJMaterialType };
    //@ts-ignore
    baseColorTexture: Cesium.Texture | undefined;
    //@ts-ignore
    normalTexture: Cesium.Texture | undefined;
    //@ts-ignore
    metallicRoughnessTexture: Cesium.Texture | undefined;
    constructor(private _container: string | HTMLElement, private _mode: 'sphere' | 'cube' | 'cylinder' = 'sphere') {
        super();
    }
    public async init() {
        //初始化创建viewer
        this.viewer = new Cesium.Viewer(this._container, {
            animation: false, // 动画控件
            baseLayerPicker: false, // 图层选择控件
            fullscreenButton: false, // 全屏控件
            geocoder: false, // 搜索控件
            homeButton: false, // 主页控件
            sceneModePicker: false, // 场景模式控件
            timeline: false, // 时间线控件
            navigationHelpButton: false, // 帮助信息控件
        })
        this.viewer.imageryLayers.removeAll();
        const baseLayer = await Cesium.TileMapServiceImageryProvider.fromUrl(
            Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII")
        )
        this.viewer.imageryLayers.addImageryProvider(baseLayer);
        //@ts-ignore
        this.viewer._cesiumWidget._creditContainer.style.display = "none"; // 去除cesium默认logo
        // this.viewer.scene.globe.show = false; // 隐藏地球
        // this.viewer.scene.skyAtmosphere.show = false; // 隐藏天空
        // this.viewer.scene.skyBox.show = false; // 隐藏天空盒
        // this.viewer.scene.fog.enabled = false; // 关闭雾化
        // this.viewer.scene.sun.show = false; // 关闭太阳
        this.viewer.scene.moon.show = false; // 关闭月亮
        // this.viewer.scene.backgroundColor = Cesium.Color.WHITE; // 设置背景色为透明
        this.viewer.scene.backgroundColor = new Cesium.Color(112 / 255.0, 128 / 255.0, 144 / 255.0, 1);
        this.ad(() => {
            if (Cesium.defined(this.viewer)) {
                this.viewer.entities.removeAll();
                this.viewer.imageryLayers.removeAll();
                this.viewer.dataSources.removeAll();
                this.viewer.scene.primitives.removeAll();
                //@ts-ignore
                let gl = this.viewer.scene.context._originalGLContext;
                gl.canvas.width = gl.canvas.height = 1;
                this.viewer.destroy();
                gl.getExtension("WEBGL_lose_context").loseContext();
                gl = null;
                this.viewer = undefined;
            }
        })
        const position = Cesium.Cartesian3.fromDegrees(116.397412, 39.90923, 50);
        const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
        // 添加球体
        await this._createModel('sphere', modelMatrix);
        // 添加立方体
        await this._createModel('cube', modelMatrix);
        // 添加圆柱体
        await this._createModel('cylinder', modelMatrix);
        this.changeModel(this._mode);
        await new Promise((resolve, reject) => {
            const listener = () => {
                //@ts-ignore
                if (this.viewer?.scene.view.viewport.width == 0) {
                    requestAnimationFrame(listener);
                } else {
                    resolve(true);
                }
            }
            requestAnimationFrame(listener);
        })

    }

    private async _createModel(mode: 'sphere' | 'cube' | 'cylinder', modelMatrix: Cesium.Matrix4) {
        this.models[mode] = await Cesium.Model.fromGltfAsync({
            // url: `${window.location.origin}/model/${mode}.glb`,
            url: `./model/${modes[mode]}.gltf`,
            modelMatrix,
            show: false, // 初始不显示
            minimumPixelSize: 200, // 最小像素大小
        })
        this.viewer?.scene.primitives.add(this.models[mode]);
    }
    public changeModel(mode: 'sphere' | 'cube' | 'cylinder') {
        for (const key in this.models) {
            if (Object.prototype.hasOwnProperty.call(this.models, key)) {
                this.models[key].show = false;
            }
        }
        this.currentModel = this.models[mode];
        this.lastMaterial && setModelMaterial(this.currentModel, this.lastMaterial);
        this.models[mode].show = true;
        this._lookAt();
    }
    public async updateMaterial(options: { [xx: string]: ESJMaterialType } | "default") {
        let hasBaseColorTexture = true;
        if (this.baseColorTexture) {
            this.baseColorTexture.texture.destroy();
            this.baseColorTexture.texture = undefined;
            this.baseColorTexture = undefined;
        }
        if (this.normalTexture) {
            this.normalTexture.texture.destroy();
            this.normalTexture.texture = undefined;
            this.normalTexture = undefined;
        }
        if (this.metallicRoughnessTexture) {
            this.metallicRoughnessTexture.texture.destroy();
            this.metallicRoughnessTexture.texture = undefined;
            this.metallicRoughnessTexture = undefined;
        }
        if (options == 'default') {
            hasBaseColorTexture = setModelMaterial(this.currentModel, "default");
            this.lastMaterial = undefined;
        } else {
            this.lastMaterial = {};
            for (const key in options) {
                const material = options[key]
                // 设置材质
                if (material.baseColorTexture && material.baseColorTexture.value != "") {
                    this.baseColorTexture = createTexture(this.viewer!, material.baseColorTexture, { magFilter: material.magFilter, minFilter: material.minFilter });
                }
                if (material.normalTexture && material.normalTexture.value != "") {
                    this.normalTexture = createTexture(this.viewer!, material.normalTexture, { magFilter: material.magFilter, minFilter: material.minFilter });
                }
                if (material.metallicRoughnessTexture && material.metallicRoughnessTexture.value != "") {
                    this.metallicRoughnessTexture = createTexture(this.viewer!, material.metallicRoughnessTexture, { magFilter: material.magFilter, minFilter: material.minFilter });
                }
                const res = await Promise.allSettled([this.baseColorTexture, this.normalTexture, this.metallicRoughnessTexture])
                //@ts-ignore
                this.baseColorTexture = res[0].value;
                //@ts-ignore
                this.normalTexture = res[1].value;
                //@ts-ignore
                this.metallicRoughnessTexture = res[2].value;
                this.lastMaterial[key] = { ...material, baseColorTexture: this.baseColorTexture, normalTexture: this.normalTexture, metallicRoughnessTexture: this.metallicRoughnessTexture };
            }
            hasBaseColorTexture = setModelMaterial(this.currentModel, this.lastMaterial);
        }
        return {
            type: hasBaseColorTexture ? 'success' : 'warn',
            message: hasBaseColorTexture ? "完成" : '部分模型颜色纹理设置失败，可能是因为模型没有baseColorTexture，或者模型加载失败'
        }
    }
    private _lookAt() {
        if (this.currentModel.ready) {
            this.viewer?.camera.lookAt(this.currentModel.boundingSphere.center, new Cesium.HeadingPitchRange(
                Cesium.Math.toRadians(-135),
                Cesium.Math.toRadians(-20),
                this.currentModel.boundingSphere.radius * 2
            ));
        } else {
            const temp = this.currentModel.readyEvent.addEventListener(() => {
                this._lookAt();
                temp();
            })
        }
    }
}